﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Windows.Forms;

namespace WWWSiteHelper
{
    [Serializable()]
    public abstract class ProjectId
    {
        public static readonly string ProjectFileExtension = ".wwwsitehelperproject";
        public abstract void CreateProject(String name);
        public abstract Project LoadProject();
        public abstract void Save(Project project);
        public abstract bool SaveFile(AbstractFile file, string content);
        public abstract string LoadFile(AbstractFile file);
    }

    [Serializable()]
    public class DefaultProjectId : ProjectId
    {
        private Dictionary<AbstractFile, String> savePaths = new Dictionary<AbstractFile, string>();

        public override void CreateProject(string name)
        {
            
        }

        public override Project LoadProject()
        {
            Project result = new Project(this);
            result.Name = "No project";
            return result;
        }

        public override void Save(Project project)
        {

        }
        public override bool SaveFile(AbstractFile file, string content)
        {
            string path;
            if (!savePaths.TryGetValue(file, out path))
            {
                SaveFileDialog dialog = new SaveFileDialog();
                dialog.Filter = TypeConverter.getFilter(file.Type);
                dialog.FileName = file.Name + "." + TypeConverter.getString(file.Type);
                if (dialog.ShowDialog() == DialogResult.OK)
                {
                    path = dialog.FileName;
                    savePaths[file] = path;
                }
                else
                    return false;
            }
            File.WriteAllText(path, content);
            return true;
        }
        public override string LoadFile(AbstractFile file)
        {
            string fullPath;
            if (!savePaths.TryGetValue(file, out fullPath))
                return "";
            if (File.Exists(fullPath))
                return File.ReadAllText(fullPath);
            else
                return "";
        }
        public AbstractFile OpenFile(string path)
        {
            string name = path.Substring(path.LastIndexOf('\\')+1);
            name = name.Substring(0,name.LastIndexOf('.'));
            AbstractFile result = new AbstractFile(name, TypeConverter.getType(path), this);
            savePaths[result] = path;
            return result;
        }
        public override bool Equals(object obj)
        {
            return obj.GetType().Equals(typeof(DefaultProjectId));
        }
        public override int GetHashCode()
        {
            return 1;
        }
    }

    [Serializable()]
    public class LocalProjectId : ProjectId
    {
        public String FileName { get; set; }
        public String GetPath()
        {
            return FileName.Substring(0, FileName.LastIndexOf('\\'));
        }

        public LocalProjectId(String fileName)
        {
            FileName = fileName;
        }
        public override void CreateProject(string name)
        {
            Project project = new Project(this);
            project.Name = name;
            Save(project);
        }
        public override Project LoadProject()
        {
            Stream input = File.OpenRead(FileName);
            BinaryFormatter deserializer = new BinaryFormatter();
            Project result = (Project)deserializer.Deserialize(input);
            input.Close();
            result.Id = this;
            return result;
        }
        public override void Save(Project project)
        {
            Stream output = File.OpenWrite(FileName);
            BinaryFormatter serializer = new BinaryFormatter();
            serializer.Serialize(output, project);
            output.Close();
        }
        public override bool SaveFile(AbstractFile file, string content)
        {
            File.WriteAllText(GetPath() + "\\" + file.Name + "." + TypeConverter.getString(file.Type), content);
            return true;
        }
        public override string LoadFile(AbstractFile file)
        {
            string fullPath = GetPath() + "\\" + file.Name + "." + TypeConverter.getString(file.Type);
            if (File.Exists(fullPath))
                return File.ReadAllText(fullPath);
            else
                return "";
        }
        public override string ToString()
        {
            return FileName;
        }
        public override bool Equals(object obj)
        {
            if (obj == this) return true;
            if (obj == null) return false;
            if (obj.GetType().Equals(this.GetType()))
            {
                return ((LocalProjectId)obj).FileName.Equals(FileName);
            }
            return false;
        }
        public override int GetHashCode()
        {
            return FileName.GetHashCode();
        }
    }

    [Serializable()]
    public class SshProjectId : ProjectId
    {
        public String Host { get; set; }
        public String Login { get; set; }
        public String Password { get; set; }
        public override void CreateProject(string name)
        {
            throw new NotImplementedException();
        }
        public override Project LoadProject()
        {
            throw new NotImplementedException();
        }
        public override void Save(Project project)
        {
            throw new NotImplementedException();
        }
        public override bool SaveFile(AbstractFile file, string content)
        {
            throw new NotImplementedException();
        }
        public override string LoadFile(AbstractFile file)
        {
            throw new NotImplementedException();
        }
    }

    [Serializable()]
    public class Project
    {
        public String Name { get; set; }
        public readonly LinkedList<AbstractFile> Files = new LinkedList<AbstractFile>();

        [NonSerialized()]
        private ProjectId projectId;
        public ProjectId Id { get { return projectId; } set { projectId = value; } }

        public Project(ProjectId id)
        {
            this.Id = id;
        }

        public void AddFile(AbstractFile file)
        {
            Files.AddLast(file);
            Save();
        }
        public void Save() { Id.Save(this); }
        public bool SaveFile(AbstractFile file, string content) { return Id.SaveFile(file, content); }
        public string LoadFile(AbstractFile file) { return Id.LoadFile(file); }
        public bool Contains(AbstractFile file) 
        {
            return Files.Contains(file);
        }
    }

}
